package net.peelmeagrape.hibernate.config;

import net.peelmeagrape.hibernate.xmlgen.XmlUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.SettingsFactory;
import org.hibernate.util.ReflectHelper;

import java.io.File;

/**
 * Custom hibernate configuration class that can handle annotated classes.
 */
public class HibernateConfiguration
        extends Configuration
{
    private static Log log = LogFactory.getLog(HibernateConfiguration.class);

    private HibernateAnnotationsProcessor annotationsProcessor =
            new HibernateAnnotationsProcessor();
    public HibernateConfiguration(SettingsFactory settingsFactory)
    {
        super(settingsFactory);
    }

    public HibernateConfiguration()
    {
    }


	public HibernateConfiguration addAnnotatedClass(Class persistentClass) throws MappingException {
        try
        {
            log.info( "Mapping class using metadata: " + persistentClass.getName() );
            Document mappingAsDom4j = annotationsProcessor.getMappingAsDom4j(persistentClass);
            if(mappingAsDom4j!=null)
            {
                log.info("Generated mapping document: "+XmlUtils.prettyPrint(mappingAsDom4j));
                add(mappingAsDom4j);
            }
            else
                log.warn("No mapping annotations found on class "+persistentClass.getName());
        }
        catch (DocumentException e)
        {
            throw new MappingException(e.getMessage(),e);
        }
        return this;
    }

	protected void parseMappingElement(Element subelement, String name) {
		Attribute rsrc = subelement.attribute( "resource" );
		Attribute file = subelement.attribute( "file" );
		Attribute jar = subelement.attribute( "jar" );
		Attribute pckg = subelement.attribute( "package" );
		Attribute clazz = subelement.attribute( "class" );
		if ( rsrc != null ) {
			log.debug( name + "<-" + rsrc );
			addResource( rsrc.getValue() );
		}
		else if ( jar != null ) {
			log.debug( name + "<-" + jar );
			addJar( new File( jar.getValue() ) );
		}
		else if ( file != null) {
			log.debug( name + "<-" + file );
			addFile( file.getValue() );
		}
		else if (pckg != null) {
            throw new MappingException("An AnnotationConfiguration instance is required to use <mapping package=\"" + pckg.getValue() + "\"/>");

		}
		else if (clazz != null) {
			log.debug( name + "<-" + clazz );
			Class loadedClass = null;
			try {
				loadedClass = ReflectHelper.classForName( clazz.getValue() );
			}
			catch (ClassNotFoundException cnf) {
				throw new MappingException("Unable to load class declared as <mapping class=\"" + clazz.getValue() + "\"/> in the configuration:", cnf);
			}
			addAnnotatedClass(loadedClass);
		}
		else {
			throw new MappingException( "<mapping> element in configuration specifies no attributes" );
		}
	}
}
